import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, forwardRef, Injector, Input, OnDestroy, Output, ViewChild } from '@angular/core';
import { AppConsts } from '@shared/AppConsts';
import { map as _map, filter as _filter, camelCase } from 'lodash-es';
import { HtmlHelper } from '@shared/helpers/HtmlHelper';
import { LayoutElement } from './layout-element';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { AppNotifyService } from '@shared/utils/service/app-notify.service';
import { AppLocalizationService } from '@app/shared/common/localization/app-localization.service';
import { ILayoutEditor } from './ILayout-editor';
import { ClipboardService } from './clipboard.service';
import { DragDropService } from './drag-drop.service';
import { debounceTime, delay, finalize, take } from 'rxjs/operators';
import { HtmlEditorModalComponent } from './html-editor-modal.component';
import { HeadingEditorModalComponent } from './Heading-editor-modal.component';
import { TextEditorModalComponent } from './Text-editor-modal.component';
import { editPropertiesModalComponent } from './edit-properties-modal.component';
import { SelectChildModalComponent } from './select-child-modal.component';
import { IToolBarItem, LayoutEditorHelper } from './layout-editor-helper';
import { AppBsModalService } from '@shared/common/appBsModal/app-bs-modal.service';
import { FileUploadHelper } from '@shared/helpers/FileUploadHelper';
import { fromEvent, Subscription } from 'rxjs';
import { FindingFileItem } from '@app/shared/common/file-finder/file-finder-options';


@Component({
    selector: 'layout-editor',
    templateUrl: './layout-editor.component.html',
    styleUrls: ['./layout-editor.component.less'],
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => LayoutEditorComponent),
            multi: true
        }
    ],
    preserveWhitespaces: false,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LayoutEditorComponent implements AfterViewInit, OnDestroy, ILayoutEditor {
    
    @Input() title: string = "";
    @Input() set data(newData: string) {
        // 数据传入时， 添加域名
        newData = HtmlHelper.getInputHtml(newData);

        if (newData === this.data) {
            return;
        }
        if (newData) {
            this.eleData = LayoutElement.fromJs(JSON.parse(newData), this);
        } 
    }

    get data(): string {
        if(!this.eleData){
            this.eleData = LayoutElement.GetDefaultData(this);
        }
        return JSON.stringify(this.eleData.toObject());
    }



    @Output() dataChange = new EventEmitter<string>();

    isEditing: boolean = false;
    isDragging: boolean = false;
    layoutIsCollapsed: boolean = false;
    contentIsCollapsed: boolean = false;

    eleData: LayoutElement = null;
    
    //剪切 和 粘贴 功能，  剪切时把选中的元素存入回收站，粘贴时把回收站中的元素加入当前选中元素的children，可以多次粘贴
    recycleBin: LayoutElement[] = [];

    layoutItems:IToolBarItem[] = [ 
        { childCount:0,displayName:'Canvas',icon: 'bi bi-pencil-square', iconText:'', title: 'Empty canvas.', className: 'layout-toolbox-item-column', type:"Canvas", contentTypeLabel:"Canvas"},
        { childCount:0,displayName:'Grid',icon: 'icon ion-grid', iconText:'', title: 'Empty grid.', className: 'layout-toolbox-item-grid', type:"Grid", contentTypeLabel:"Grid"},
        { childCount:1,displayName:'Row',icon: 'icon ion-navicon-round', iconText:'', title: 'Row with 1 column.', className: 'layout-toolbox-item-row',  type:"Row", contentTypeLabel:"Row"},
        //{ childCount:2,displayName:'Row (2 column)',icon: 'icon ion-navicon-round', iconText:'', title: 'Row with 2 columns.', className: 'layout-toolbox-item-row', type:"Row", contentTypeLabel:"Row"},
        //{ childCount:3,displayName:'Row (3 column)',icon: 'icon ion-navicon-round', iconText:'', title: 'Row with 3 columns.', className: 'layout-toolbox-item-row', type:"Row", contentTypeLabel:"Row"},
        //{ childCount:4,displayName:'Row (4 column)',icon: 'icon ion-navicon-round', iconText:'', title: 'Row with 4 columns.', className: 'layout-toolbox-item-row', type:"Row", contentTypeLabel:"Row"},
        //{ childCount:6,displayName:'Row (6 column)',icon: 'icon ion-navicon-round', iconText:'', title: 'Row with 6 columns.', className: 'layout-toolbox-item-row', type:"Row", contentTypeLabel:"Row"},
        { childCount:0,displayName:'Column',icon: 'bi bi-layout-split', iconText:'', title: 'Empty column.', className: 'layout-toolbox-item-column', type:"Column", contentTypeLabel:"Column"},
    ];
    contentItems:IToolBarItem[] = [ 
        { childCount:0,displayName:'Divider',icon: 'bi bi-dash', iconText:'', title: 'Divider element.', className: 'layout-toolbox-item-content', type:"Content", contentTypeLabel:"Divider"},
        { childCount:0,displayName:'Heading h1-h6',icon: '', iconText:'H', title: 'Heading h1-h6 element.', className: 'layout-toolbox-item-content', type:"Content", contentTypeLabel:"Heading"},
        { childCount:0,displayName:'Text',icon: 'bi bi-file-richtext', iconText:'', title: 'HTML element.', className: 'layout-toolbox-item-content', type:"Content", contentTypeLabel:"Html"},
        //{ childCount:0,displayName:'Text',icon: 'bi bi-file-text', iconText:'', title: 'Text element.', className: 'layout-toolbox-item-content', type:"Content", contentTypeLabel:"Text"},
        { childCount:0,displayName:'Image',icon: 'bi bi-file-image', iconText:'', title: 'Image element.', className: 'layout-toolbox-item-content', type:"Content", contentTypeLabel:"Image"},
        { childCount:0,displayName:'Video',icon: 'bi bi-file-play', iconText:'', title: 'Video element.', className: 'layout-toolbox-item-content', type:"Content", contentTypeLabel:"Video"}
    ];

    focusedElement:LayoutElement = null;
    dropTargetElement:LayoutElement = null;

    isProccessingDrag = false;
    isAcceptDragItem = false;

    clipboard: ClipboardService;

    randomId:string;
    private subscription : Subscription;

    constructor(
        private notify: AppNotifyService,
        private _appLocalizationService: AppLocalizationService,
        private _dragDropService:DragDropService,
        private _modalService: AppBsModalService

    ) {
        this.clipboard = new ClipboardService();

        this.randomId = FileUploadHelper.randomId();
    }

    // let outputData = HtmlHelper.getOutputHtml(newData);
    ngAfterViewInit() {
        let modals = document.querySelectorAll('.modal.fade.show');
        if(modals.length > 0){
            let div =  (modals[modals.length - 1] as HTMLElement);
            this.subscription = fromEvent(div,'scroll')
            .pipe( 
                debounceTime(200)
            )
            .subscribe( _ =>{
                const ele = document.getElementById('l' + this.randomId);
                const rect = ele.getBoundingClientRect();
                if(rect){
                    if(rect.top < 0){
                        const tool = document.getElementById('tool'+ this.randomId);
                        const toolRect = tool.getBoundingClientRect();
                        if(rect.bottom > toolRect.height){
                            tool.style.position = "fixed";
                            tool.style.top = "0";
                        }else{
                            tool.style.position = "fixed";
                            tool.style.top = (rect.bottom - toolRect.height) +'px';
                        }
                    }else{
                        const tool = document.getElementById('tool'+ this.randomId);
                        tool.style.position = "";
                        tool.style.top = "";
                    }
                }
            });
        }else{
            this.subscription = fromEvent(window,'scroll')
            .pipe( 
                debounceTime(200)
            )
            .subscribe( _ =>{
                const ele = document.getElementById('l' + this.randomId);
                const rect = ele.getBoundingClientRect();
                if(rect){
                    if(rect.top < 0){
                        const tool = document.getElementById('tool'+ this.randomId);
                        const toolRect = tool.getBoundingClientRect();
                        if(rect.bottom > toolRect.height){
                            tool.style.position = "fixed";
                            tool.style.top = "110px";
                        }else{
                            tool.style.position = "fixed";
                            tool.style.top = (rect.bottom - toolRect.height) +'px';
                        }
                    }else{
                        const tool = document.getElementById('tool'+ this.randomId);
                        tool.style.position = "";
                        tool.style.top = "";
                    }
                }
            });
        }
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }

    toggleLayoutIsCollapsed($event) {
        this.layoutIsCollapsed = !this.layoutIsCollapsed;
    }
    toggleContentIsCollapsed($event) {
        this.contentIsCollapsed = !this.contentIsCollapsed;
    }

    mouseEnter(item: LayoutElement, e: Event) {
        if(this.isDragging){
            e.stopPropagation();
            return;
        }

        LayoutElement.alterAlongTree(this.eleData, (t) => { 
            if(t.id !== item.id){
                t.isActive = false;
            }
         });
        if(item.isFocused){
            return;
        }
        
        item.isActive = true;

        e.stopPropagation();
    }

    mouseLeave(item: LayoutElement, e: Event) {
        if(this.isDragging){
            e.stopPropagation();
            return;
        }

        item.isActive = false;

        
        e.stopPropagation();
    }

    dragenter(item: LayoutElement, e: DragEvent) {
        // 判别是否可移入，调整样式，  this.isDragging = true
        if(this.isProccessingDrag){
            e.preventDefault(); 
            e.stopPropagation();
            return;
        }

        this.isProccessingDrag = true;
        this._dragDropService.getDragData().pipe(take(1))
        .pipe(delay(100))
        .pipe(finalize(() => this.isProccessingDrag = false))
        .subscribe(dragData =>{
            if (this.isDragging) {
                let data = dragData.data;
                data.isDropingItem = true;

                let offsetIndex = 0;
                let containerDiv = e.target as HTMLElement;
                if(containerDiv){
                    let clientWidth = containerDiv.clientWidth;
                    let clientHeight = containerDiv.clientHeight;
                    if(item.type === "Column"){
                        if((e.offsetX * 2) > clientWidth){
                            offsetIndex = 1;
                         }
                    }else{
                        if((e.offsetY * 2) > clientHeight){
                            offsetIndex = 1;
                         }
                    }
                }

                this.dropTargetElement = item.insertRecursively(data ,offsetIndex);
                if (this.dropTargetElement) {
                    this.dropTargetElement.isDropTarget = true;
                }
            }
        });
        
        if(this.dropTargetElement){
            LayoutElement.alterAlongTree(this.eleData, (t) => { 
                if(t.id !== this.dropTargetElement.id){
                    t.isDropTarget= false;
                }
            });
        }

        e.preventDefault(); 
        e.stopPropagation();
    }

    dragleave(item: LayoutElement, e: DragEvent) {
        e.preventDefault(); 
        e.stopPropagation();
    }
    dragPause(item: LayoutElement, e: DragEvent){
        e.preventDefault(); 
        e.stopPropagation();
    }
    dragover(item: LayoutElement, e: DragEvent) {
        //需要支持多级拖拽，所以要防止事件冒泡
        e.preventDefault(); 
        e.stopPropagation();

        this.dragenter(item,e);
    }
    drop(item: LayoutElement, e: DragEvent) {
        e.preventDefault(); 
        e.stopPropagation();
        console.log("drop")
       // console.log(e)

       LayoutElement.alterAlongTree(this.eleData, (t) => { 
            if(t.isDropingItem){
                t.isDropingItem = false;
                t.setIsFocused();
                this.isAcceptDragItem = true;
            }
        });
    }

    dragstart(item: IToolBarItem, e: DragEvent) {
        //console.log("dragstart");
        //console.log(e);
        this.isDragging = true;

        let newItem = LayoutEditorHelper.getDragingItem(item, this);
        this._dragDropService.setDragData({id: newItem.id, data:newItem});
    }
    dragend(item: IToolBarItem, e: DragEvent) {
        // 结束拖拽进程， 恢复鼠标样式
        console.log("dragend")
        //console.log(e)
        
        this.isDragging = false;
    
        LayoutElement.alterAlongTree(this.eleData, (t) => { 
            if(t.isDropingItem){
                t.parent.children =  t.parent.children.filter(tt=> tt.id !== t.id);
            }else{
                t.isDropTarget = false;
            }
        });

        this._dragDropService.clearDragData();
        if(this.isAcceptDragItem){
            this.isAcceptDragItem = false;
            this.dataChange.emit(this.data);
            if(this.focusedElement){
                this.edit(this.focusedElement);
            }
        }
    }

    click(item: LayoutElement, e: Event) {
        if(this.isDragging){
            return;
        }

        if(!item){
            LayoutElement.alterAlongTree(this.eleData, (t) => {
                t.isSelected = false;
                t.isFocused = false;
            });
            e.stopPropagation();

            return;
        }

        item.setIsFocused();

        e.stopPropagation();
    }

    keydown(e:KeyboardEvent){
        if (this.isDragging)
            return;

        let focusedElement = this.focusedElement;
        if (!this.clipboard.isDisabled) {
            if (!!focusedElement) {
                if (e.code) {
                    switch (e.code) {
                        case 'KeyC':
                            if (e.ctrlKey) {
                                focusedElement.copy(this.clipboard);
                            }
                            return;
                        case 'KeyV':
                            if (e.ctrlKey) {
                                focusedElement.paste(this.clipboard);
                            }
                            return;
                        case 'KeyX':
                            if (e.ctrlKey) {
                                focusedElement.cut(this.clipboard);
                            }
                            return;
                        case 'KeyZ':
                            if (e.ctrlKey) {
                                focusedElement.unDelete();
                            }
                            return;
                    }
                }
            }
        }

        if (!!focusedElement) {
            if (e.code) {
                switch (e.code) {
                    case 'ArrowLeft':
                        if(focusedElement.type ==="Column"){
                            if(e.shiftKey){
                                focusedElement.decreaseColumnWidth();
                                return;
                            }
                            if(e.ctrlKey){
                                focusedElement.moveUp();
                                return;
                            }
                            if(!e.altKey){
                                focusedElement.parent.moveFocusPrevChild(focusedElement);
                                return;
                            }
                        }
                        return;
                    case 'ArrowUp':
                        if(e.shiftKey){
                            focusedElement.selectParent();
                            return;
                        }
                        if(e.ctrlKey){
                            focusedElement.moveUp();
                            return;
                        }
                        if(!e.shiftKey && !e.altKey){
                            focusedElement.parent.moveFocusPrevChild(focusedElement);
                            return;
                        }
                        return;
                    case 'ArrowDown':
                        if(e.shiftKey){
                            focusedElement.selectFirstChild();
                            return;
                        }
                        if(e.ctrlKey){
                            focusedElement.moveDown();
                            return;
                        }
                        if(!e.shiftKey && !e.altKey){
                            focusedElement.parent.moveFocusNextChild(focusedElement);
                            return;
                        }
                        return;
                    case 'ArrowRight':
                        if(focusedElement.type ==="Column"){
                            if(e.shiftKey){
                                focusedElement.increaseColumnWidth();
                                return;
                            }
                            if(e.ctrlKey){
                                focusedElement.moveDown();
                                return;
                            }
                            if(!e.altKey){
                                focusedElement.parent.moveFocusNextChild(focusedElement);
                                return;
                            }
                        }
                        return;
                    case 'Delete':
                        if(!e.ctrlKey && !e.shiftKey && !e.altKey){
                            focusedElement.delete();
                        }
                        return;
                    case 'Enter':
                        if(!e.ctrlKey && !e.shiftKey && !e.altKey && focusedElement.hasEditor){
                            // 打开编辑器
                            this.edit(focusedElement);
                        }
                        return;
                }
            }
        }

        //TODO:补充其他操作
    }

    editProperties(item: LayoutElement){
        const bsModalRef = this._modalService.show(editPropertiesModalComponent, {
            backdrop: 'static', class: 'modal-xl'
        });

        bsModalRef.content.shown(item);
        bsModalRef.content.callback = () => {
            this.editCallBack();
        };
    }

    edit(item: LayoutElement){
        if(!item.canEdit()){
            return;
        }

        if (item.contentTypeLabel === "Html") {
            const bsModalRef = this._modalService.show(HtmlEditorModalComponent, {
                backdrop: 'static', class: 'modal-xl'
            });
    
            bsModalRef.content.shown(item);
            bsModalRef.content.callback = () => {
                this.editCallBack();
            };
            return;
        } 
        
        if (item.contentTypeLabel === "Text") {
            const bsModalRef = this._modalService.show(TextEditorModalComponent, {
                backdrop: 'static', class: 'modal-xl'
            });
    
            bsModalRef.content.shown(item);
            bsModalRef.content.callback = () => {
                this.editCallBack();
            };
            return;
        } 
        
        if (item.contentTypeLabel === "Heading") {
            const bsModalRef = this._modalService.show(HeadingEditorModalComponent, {
                backdrop: 'static', class: 'modal-xl'
            });
    
            bsModalRef.content.shown(item);
            bsModalRef.content.callback = () => {
                this.editCallBack();
            };
            return;
        } 
        
        if (item.contentTypeLabel === "Image") {
            abp.event.trigger('abp.ckeditor.filefinder', { editor:null, multiSelect: false, canUploadImg: true, callback: (list: FindingFileItem[])=>{
                if(list.length === 0){
                    item.setItemData('');
                }else{
                    item.setItemData(HtmlHelper.getOutputHtml(list[0].fileUrl));
                }
                item.setItemHtml();
                this.dataChange.emit(this.data);
            } });
            return;
        }

        if (item.contentTypeLabel === "Video") {
            abp.event.trigger('abp.ckeditor.filefinder', { editor:null, multiSelect: false, canUploadImg: true, callback: (list: FindingFileItem[])=>{
                if(list.length === 0){
                    item.setItemData('');
                }else{
                    item.setItemData(HtmlHelper.getOutputHtml(list[0].fileUrl));
                }
                item.setItemHtml();
                this.dataChange.emit(this.data);
            } });
            return;
        }
    }

    editCallBack(){
        this.dataChange.emit(this.data);
    }

    add(item: LayoutElement){
        const bsModalRef = this._modalService.show(SelectChildModalComponent, {
            backdrop: 'static', class: 'modal-xs'
        });

        bsModalRef.content.shown(item);
        bsModalRef.content.callback = (newChild: LayoutElement) => {
            this.addCallBack(newChild);
        };
    }
    addCallBack(item: LayoutElement){
        this.dataChange.emit(this.data);
        item.setIsFocused();
        this.edit(item);
    }
}